package public

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"github.com/go-redis/redis"
	"math/rand"
	"strconv"
	"time"
)

func UInt64ToImei(num uint64) uint64 {
	left := num / 1000000000000
	var imei uint64
	switch left {
	case 0:
		imei = num + 35000000000000
	case 1:
		imei = num + 85000000000000
	default:
		imei = num + 97000000000000
	}
	return imei
}

func Md5ToImei(s string) uint64 {
	var n uint64
	for _, c := range []byte(s) {
		var d byte
		switch {
		case '0' <= c && c <= '9':
			d = c - '0'
		case 'a' <= c && c <= 'z':
			d = c - 'a' + 10
		case 'A' <= c && c <= 'Z':
			d = c - 'A' + 10
		}
		n *= uint64(16)
		n1 := n + uint64(d)
		n = n1 % 3000000000000
	}
	return UInt64ToImei(n)
}

func ImeiToMd5(imei uint64) string {
	ctx := md5.New()
	ctx.Write([]byte(fmt.Sprintf("%d", imei)))
	return hex.EncodeToString(ctx.Sum(nil))
}

func RandomImei() uint64 {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	num := uint64(r.Int63n(3000000000000))
	return UInt64ToImei(num)
}

func ImeiToImei(cycle int, imei uint64) uint64 {
	newImei := imei
	for i := 0; i < cycle; i++ {
		md5Str := ImeiToMd5(newImei)
		newImei = Md5ToImei(md5Str)
	}
	return newImei
}

func QueryMd5Imei(rds *redis.Client, cycle int, imeiMd5 string) uint64 {
	var md5Str string
	md5Str = imeiMd5
	for i := 0; i < cycle; i++ {
		imei := Md5ToImei(md5Str)
		key := fmt.Sprintf("%d", imei)
		val, err := rds.Get(key).Result()
		if err != nil {
			md5Str = ImeiToMd5(imei)
			continue
		}
		originImei, err := strconv.ParseUint(val, 10, 64)
		if err != nil {
			md5Str = ImeiToMd5(imei)
			continue
		}
		imei = QueryImei(cycle, originImei, imeiMd5)
		if imei == 0 {
			// 不是目标链
			md5Str = ImeiToMd5(imei)
			continue
		}
		return imei
	}
	return 0
}

func QueryImei(cycle int, originImei uint64, imeiMd5 string) uint64 {
	newImei := originImei
	var matchFlag bool
	for i := 0; i < cycle; i++ {
		md5Str := ImeiToMd5(newImei)
		if md5Str == imeiMd5 {
			matchFlag = true
			break
		}
		newImei = Md5ToImei(md5Str)
	}
	if matchFlag {
		return newImei
	}
	return 0
}
